<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<script type="text/javascript">
    // 一、原型测试题
		function Parent() {
            this.a = 1;
            this.b = [1, 2, this.a]; 
            // 这里的 this.a 不是动态的，是在实例化 Praent 中已经确定的值 1，不受其他影响
            this.c = { demo: 5 };
            this.show = function () {
                console.log(this.a , this.b , this.c.demo );
            }
        }
		function Child() {
		    this.a = 2;
		    this.change = function () {
		        this.b.push(this.a);
		        this.a = this.b.length;
		        this.c.demo = this.a++;
		    }
		}
        Child.prototype = new Parent(); 
        var parent = new Parent();
        var child1 = new Child();
        var child2 = new Child();
        child1.a = 11;
        child2.a = 12;
        parent.show(); // 直接调用 Parent 构造函数中的 show 方法
        child1.show(); // Child 构造函数中没有 show 方法，向上寻找，去 Child.prototype中寻找，恰好Child.prototype原型对象是 Parent 构造函数的一个实例，拥有Praent构造函数中的所有属性和方法，于是，可以调用 其中的 show 方法
        /*
	1、调用 this.show ，取a的值时，因为child1实例本事有a的值，所以不会向上去原型对象中去寻找，所以 a = 11
	2、this.b，因为child1上没有b属性，所以，会去原型对象中查找，this.b = [1, 2, this.a]; 但这里的this.a不是当前实例的this.a,这里的 this.a其实是一个定值，因为在继承Parent构造函数时，已经执行过一次，所以，这里的this.b = [1, 2, 1]，是一个固定的值
	3、同样，child1实例也没有c属性，也在原型对象找寻找，即为c = { demo: 5 }
	最终输出为 11 [1, 2, 1] 5
        */
        child2.show(); // 同上 12 [1, 2, 1] 5
        child1.change(); // 执行自身的 change 方法
        /*
	1、通过以上步骤得知 child1的 a、b、c 为 11 [1, 2, 1] 5
	2、执行change方法时,this.b = [1, 2, 1, 11]; this.a = 4;
	3、 this.a++,先赋值后计算，所以这时 this.a = 5,this.c.demo = 4
	4、这里的this.c.demo受到 childe2对象的change方法影响，这里执行完后是 4，立即执行show方法即可打印出来
        */
        child2.change();
        /*
        1、实例会共享一个原型对象，所以，child1修改了b和c属性时，child2也会获取修改后的b和c属性，只有a时他们自身的属性，不受影响
        2、this.b = [1, 2, 1, 11, 12] this.a = 5
        3、this.c.demo = this.a++,所以，之后访问this.b.length时，的值是5，this.a = 6
        4、所以，接下来打印show方法时 this.c.demo  = 5
        */
        parent.show();
        child1.show();
        child2.show();
        let obj = {
        	a: 1,
        	b: 2
        }
        function fff(){}
        console.log(fff.prototype.constructor)
        console.log(child1.__proto__,Object.getPrototypeOf(child1))
        console.log(obj.__proto__,Object.getPrototypeOf(obj))

        function Person(){ // 构造函数
            this.name = 'zxw';
            this.age = '666';
            this.show = function(){
                console.log(this.name,this.age)
            }
        }
        Person.prototype.name = '原型对象111' // 原型
        let parent1 = new Person() // 实例对象
        console.log(Person.prototype === parent1.__proto__)
        Person.prototype = {a:666}
        /*
        实例对象创建在重写原型对象之前，则实例指向的__proto__指向重写后的原型对象
        实例对象创建在重写原型对象之后，则实例对象的原型指向最初的原型对象，
        */
        console.log(parent1.constructor)
        console.log(parent1 instanceof Person)
        console.log(Person.prototype === parent1.__proto__)
        console.log(Object.getPrototypeOf(parent1))

    // 二、 constructor、instanceof、Object.getPrototypeOf 分别指向原型还是什么？
        function fun(){}
        fun.prototype = {    
            name : 'peter',    
            age : 25    
        }
        var a = new fun();
        var b = new fun();
        fun.prototype.name = 'jack';
        console.log(a.name, b.name);//jack jack
        fun.prototype = {};
        fun.prototype.name = 'tom';
        console.log(a.name, b.name); //jack jack
        console.log('重写之后的原型对象：',fun.prototype)
        /*
        没有重写原型对象时，例如第一个构造函数 Person,创建的实例对象 parent1的constructor属性指向构造函数Person,
        但是在实例对象 a和b 创建之前，fun的原型对象被重写，所以，在实例化的过程中，新创建对象的__proto__指向的是重写之后的原型对象，所以，a.constructor指向的是 Object的构造函数，而不是fun构造函数。
        因为在创建 a b 实例对象之后，fun又重新改写了原型对象，所以，实例的__proto__指向的仍然是改写之前的原型，所以，构造函数的原型是不在 a b 实例对象的原型链上的
        重写之后的原型对象是new Object().__proto__ = {},而不是函数的prototype属性，所以，b.constructor指向的是Object的构造函数；而上边的第一个例子,虽然也经过了重写原型对象，但是是在实例化对象之后重写的，所以parent1.constructor指向的是构造函数Person,
        */
        console.log('1',b.constructor === fun)  //1 false
        console.log('2',b instanceof fun)  //2 false
        b.constructor.prototype.name = 'kitty'; //b.constructor.prototype指向的是fun的prototype
        console.log(a.name, b.name); //jack jack
	</script>
</body>
</html>